package tmt.usercenter.web.plugin.datatable;

import com.tmt.datatable.TableResponse;
import com.tmt.datatable.editor.ext.fileinfo.DefaultFileInfoLoader;
import com.tmt.datatable.editor.ext.select2.Select2OptionValueLoader;
import com.tmt.datatable.model.FileWrapper;
import com.tmt.fileservice.IFileService;
import com.tmt.helper.ReflectHelper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tmt.usercenter.web.Application;
import tmt.usercenter.web.domain.enums.AuthorityItem;
import tmt.usercenter.web.domain.security.UserDetailsImpl;
import tmt.usercenter.web.plugin.editormodel.FileInfoFinder;
import tmt.usercenter.web.service.TmtUserService;

import javax.persistence.Id;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Objects;

/**
 * Created by ThreeManTeam on 2017/6/15.
 */

@Aspect
@Service
@Transactional(readOnly = true)
@Slf4j
public class TableResponseInterceptor {

	@Autowired
	private IFileService fileService;

	@Autowired
	private TmtUserService userService;

	@Pointcut("execution(* com.tmt.datatable.ext.controller.ITmtBaseService.queryByRequest(..))")
	public void onExecute() {
	}

	@Before(value = "onExecute()")
	public void initialAdditionalConditionForQueryByRequest(JoinPoint joinPoint) {
		initialLimitedCondition(joinPoint, 1, 6);
	}

	/**
	 * 为TableResponse对象返回的数据记录添加绑定文件信息。
	 *
	 * @param joinPoint
	 * @param result
	 */
	@AfterReturning(value = "onExecute()", returning = "result")
	public void loadFileInfo(JoinPoint joinPoint, Object result) {
		try {
			TableResponse response = ((AsyncResult<TableResponse>) result).get();
			if (response.getData() != null && response.getData().size() > 0) {
				FileInfoFinder fileInfoFinder = new FileInfoFinder(fileService);
				FileWrapper fileWrapper = DefaultFileInfoLoader.getFileWrapper(response.getData(), Id.class, true, fileInfoFinder);
				response.setFiles(fileWrapper);
			}
		} catch (Exception ignored) {
		}
	}

	/**
	 * 为TableResponse对象返回的数据记录添加可选信息，例如：页面上的Select2插件的Options数据。
	 *
	 * @param joinPoint
	 * @param result
	 */
	@AfterReturning(value = "onExecute()", returning = "result")
	public void loadSelect2Options(JoinPoint joinPoint, Object result) {
		try {
			log.debug("-----------------loadSelect2Options----------------------");
			TableResponse response = ((AsyncResult<TableResponse>) result).get();
			if (response.getData() != null && response.getData().size() > 0) {
				Select2OptionValueLoader.loadSelect2OptionValue(response.getData(), response.getOptions(), null);
			}
		} catch (Exception ignored) {
		}
	}

	@Pointcut("execution(* com.tmt.datatable.ext.controller.ITmtBaseService.findForSelect2(..))")
	public void onExecute1() {
	}


	@Before(value = "onExecute1()")
	public void initialAdditionalConditionForFindForSelect2(JoinPoint joinPoint) {
		initialLimitedCondition(joinPoint, 0, 8);
	}

	private void initialLimitedCondition(JoinPoint joinPoint, int targetClazzParamPos, int mapParamPos) {
		log.debug("-----------------initialAdditionalCondition----------------------");
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication == null || !authentication.isAuthenticated())
			return;

		UserDetailsImpl details = ((UserDetailsImpl) authentication.getPrincipal());
		details = userService.getUserDetailsImpl(details.getUserId(), Application.SYSTEM_ID);
		if (details.getAuthorities().stream().anyMatch(x ->
				Objects.equals(x.getAuthority(), AuthorityItem.System_Data_Across_Access.name()))) {
			return;
		}

		Class<?> clazz = (Class<?>) joinPoint.getArgs()[targetClazzParamPos];

		//如果用户具备Client_Data_Across_Access权限，则将其访问的数据限制在客户系统内。
		if (details.getAuthorities().stream().anyMatch(x ->
				Objects.equals(x.getAuthority(), AuthorityItem.Client_Data_Across_Access.name()))) {
			Field field = ReflectHelper.findFieldByName(clazz, "originSystem");
			if (field != null) {
				Long id = userService.findOriginSystemIdByUsername(details.getUsername());
				Map<String, String[]> map = (Map<String, String[]>) joinPoint.getArgs()[mapParamPos];
				map.put("originSystem.id", new String[]{id.toString()});
				return;
			}
		}

		//如果用户不具备任何数据交叉访问能力，则只能访问自己创建的数据。
		Field field = ReflectHelper.findFieldByName(clazz, "creator");
		if (field != null) {
			Map<String, String[]> map = (Map<String, String[]>) joinPoint.getArgs()[mapParamPos];
			map.put("creator.id", new String[]{"" + details.getUserId()});
		}
	}

}
